#include <ros/ros.h>
#include <geometry_msgs/Twist.h>
#include <geometry_msgs/Pose2D.h>
#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>

double x = 0.0;
double y = 0.0;
double th = 0.0;

double vx = 0.0;
double vy = 0.0;
double vth = 0.0;

ros::Time current_time, last_time;

void vel_callback(const geometry_msgs::Twist::ConstPtr& vel)
{
    //get current velocity
    vx = vel->linear.x;
    vy = vel->linear.y;
    vth = vel->angular.z;

    current_time = ros::Time::now();
    //compute odometry in a typical way given the velocities of the robot
    double dt = (current_time - last_time).toSec();
    double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
    double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
    double delta_th = vth * dt;

    x += delta_x;
    y += delta_y;
    th += delta_th;
    last_time = current_time;
}

int main(int argc, char** argv)
{
    ros::init(argc, argv, "odometry_publisher");
    ros::NodeHandle n;
    ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);
    ros::Publisher pose2d_pub = n.advertise<geometry_msgs::Pose2D>("odom_pose2d", 50);
    ros::Subscriber cmd_sub = n.subscribe<geometry_msgs::Twist>("real_vel",10, vel_callback);
    tf::TransformBroadcaster odom_broadcaster;

    current_time = ros::Time::now();
    last_time = ros::Time::now();
    ros::Rate r(50.0);
    while(ros::ok()) {

        ros::spinOnce(); // check for incoming messages
        
        geometry_msgs::Pose2D pose2d;
        pose2d.x = x;
        pose2d.y = y;
        pose2d.theta = th;
        pose2d_pub.publish(pose2d);
        //since all odometry is 6DOF we'll need a quaternion created from yaw
        geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);

        //first, we'll publish the transform over tf
        geometry_msgs::TransformStamped odom_trans;
        odom_trans.header.stamp = current_time;
        odom_trans.header.frame_id = "odom";
        odom_trans.child_frame_id = "base_footprint";

        odom_trans.transform.translation.x = x;
        odom_trans.transform.translation.y = y;
        odom_trans.transform.translation.z = 0.0;
        odom_trans.transform.rotation = odom_quat;

        //send the transform
        odom_broadcaster.sendTransform(odom_trans);

        //next, we'll publish the odometry message over ROS
        nav_msgs::Odometry odom;
        odom.header.stamp = current_time;
        odom.header.frame_id = "odom";

        //set the position
        odom.pose.pose.position.x = x;
        odom.pose.pose.position.y = y;
        odom.pose.pose.position.z = 0.0;
        odom.pose.pose.orientation = odom_quat;

        //set the velocity
        odom.child_frame_id = "base_footprint";
        odom.twist.twist.linear.x = vx;
        odom.twist.twist.linear.y = vy;
        odom.twist.twist.angular.z = vth;
        //publish the message
        odom_pub.publish(odom);
        r.sleep();
    }
}
